import XLSX from 'xlsx'
import XLSXStyle from 'xlsx-style'
import { saveAs } from 'file-saver'

function s2ab (s) {
  var buf = new ArrayBuffer(s.length)
  var view = new Uint8Array(buf)
  for (var i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF
  return buf
}
// 将一个sheet转成最终的excel文件的blob对象，然后利用URL.createObjectURL下载
function sheet2blob (sheet, sheetName) {
  sheetName = sheetName || 'sheet1'
  var workbook = {
    SheetNames: [sheetName],
    Sheets: {}
  }
  workbook.Sheets[sheetName] = sheet // 生成excel的配置项

  var wopts = {
    bookType: 'xlsx', // 要生成的文件类型
    bookSST: false, // 是否生成Shared String Table，官方解释是，如果开启生成速度会下降，但在低版本IOS设备上有更好的兼容性
    type: 'binary'
  }
  var wbout = XLSX.write(workbook, wopts)
  var blob = new Blob([s2ab(wbout)], {
    type: 'application/octet-stream'
  }) // 字符串转ArrayBuffer
  return blob
}

function openDownloadDialog (url, saveName) {
  if (typeof url === 'object' && url instanceof Blob) {
    url = URL.createObjectURL(url) // 创建blob地址
  }
  var aLink = document.createElement('a')
  aLink.href = url
  aLink.download = saveName || '' // HTML5新增的属性，指定保存文件名，可以不要后缀，注意，file:///模式下不会生效
  var event
  if (window.MouseEvent) event = new MouseEvent('click')
  else {
    event = document.createEvent('MouseEvents')
    event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
  }
  aLink.dispatchEvent(event)
}

/**
 * 导出带样式的自定义报表
 * @param companyName 公司名称 string
 * @param stopReason 停机原因 string
 * @param position 所在位置 string
 * @param tableHead 表头 string
 * @param tableData 表格数据二维数组，数组里是每一行的数据 [[], [], []]
 * @param excelName 表格的名称
 * @param undesirableReason 不良原因 string
 * @param countTime 统计时间 string
 */
export function exportCustomExcel (companyName, stopReason, position, tableHead, tableData, excelName) {
  const length = tableHead.length - 1
  // 合并公司名称
  const companyMerge = {
    s: {// s为开始
      c: 0, // 开始列
      r: 0// 开始取值范围
    },
    e: {// e结束
      c: length, // 结束列
      r: 0// 结束范围
    }
  }
  // 合并停机原因单元格
  const stopReasonMerge = {
    s: {// s为开始
      c: 0, // 开始列
      r: 1// 开始取值范围
    },
    e: {// e结束
      c: length, // 结束列
      r: 1// 结束范围
    }
  }
  // 合并所在位置单元格
  const positionMerge = {
    s: {// s为开始
      c: 0, // 开始列
      r: 2// 开始取值范围
    },
    e: {// e结束
      c: length, // 结束列
      r: 2// 结束范围
    }
  }

  // 添加标题，停机原因，所谓位置数据
  const ws = XLSX.utils.aoa_to_sheet([[companyName], [stopReason], [position]])

  // 添加标题栏
  XLSX.utils.sheet_add_aoa(ws, [tableHead], { origin: 'A4' })
  // 添加表格内部数据
  XLSX.utils.sheet_add_aoa(ws, tableData, { origin: 'A5' })
  // 上右下左的border
  const borderAll = { // 单元格外侧框线
    top: {
      style: 'thin'
    },
    bottom: {
      style: 'thin'
    },
    left: {
      style: 'thin'
    },
    right: {
      style: 'thin'
    }
  }
  // 居中
  const alignCenter = {
    horizontal: 'center',
    vertical: 'center'
  }
  // 设置公司名称的样式
  ws['A1'].s = {
    fill: {
      fgColor: {
        rgb: 'FF2F75B5' // 背景颜色,不要在前面加#号
      }
    },
    font: {
      name: '宋体',
      sz: 16,
      color: { rgb: 'FFFFFFFF' },
      bold: false,
      italic: false,
      underline: false
    },
    alignment: alignCenter
  }
  // 设置停机原因的样式
  ws['A2'].s = {
    font: {
      name: '宋体',
      sz: 12,
      color: { rgb: '#FFFF0000' },
      bold: true,
      italic: false,
      underline: false
    },
    alignment: alignCenter
  }
  // 设置所在位置的样式
  ws['A3'].s = {
    font: {
      name: '宋体',
      sz: 12
    }
  }
  // 创建一个空的sheet
  const wb = XLSX.utils.book_new()
  // 添加合并的config
  ws['!merges'] = [companyMerge, stopReasonMerge, positionMerge]
  // 动态计算每一列的宽度
  const colWidth = [...tableData, [...tableHead]].map(row => row.map(val => {
    /* 先判断是否为null/undefined */
    if (!val) {
      return {
        'wch': 10
      }
      // 判断是否为中文
    } else if (/[\u4e00-\u9fa5]/.test(val.toString())) {
      return {
        'wch': val.toString().length * 2 > 10 ? val.toString().length * 2 : 10
      }
    } else {
      return {
        'wch': val.toString().length > 10 ? val.toString().length : 10
      }
    }
  }))
  // 每一列取最大宽度
  let result = colWidth[0]
  for (let i = 1; i < colWidth.length; i++) {
    for (let j = 0; j < colWidth[i].length; j++) {
      if (result[j]['wch'] < colWidth[i][j]['wch']) {
        result[j]['wch'] = colWidth[i][j]['wch']
      }
    }
  }
  ws['!cols'] = result
  // 给表头动态添加样式
  // 第4行为表头行，通过正则匹配所有第四行
  Object.keys(ws).forEach(item => {
    if (/[A-Z]+4$/.test(item)) {
      ws[item].s = {
        border: borderAll,
        fill: {
          fgColor: {
            rgb: 'FF93CDDD' // 背景颜色,不要在前面加#号
          }
        },
        alignment: alignCenter
      }
    } else {
      // 内容区的样式，添加border和居中
      if (!ws[item].s && ws[item].t) {
        ws[item].s = {
          border: borderAll,
          alignment: alignCenter
        }
      }
    }
  })
  // 添加sheet
  XLSX.utils.book_append_sheet(wb, ws, excelName)
  const wbout = XLSXStyle.write(wb, {
    bookType: 'xlsx',
    bookSST: false,
    type: 'binary'
  })
  saveAs(new Blob([s2ab(wbout)], {
    type: 'application/octet-stream'
  }), `${excelName}.xlsx`)
}
// 生产计数统计报表
export function exportDeviceExcel (companyName, stopReason, position, pubData, tableHead, tableData, excelName) {
  const length = tableHead.length - 1
  var pubDataMap = {}
  pubData.forEach(v1 => {
    pubDataMap[v1.deviceId] = v1.resultTimeAndCount
  })
  // 合并公司名称
  const companyMerge = {
    s: {// s为开始
      c: 0, // 开始列
      r: 0// 开始取值范围
    },
    e: {// e结束
      c: length, // 结束列
      r: 0// 结束范围
    }
  }
  // 合并停机原因单元格
  const stopReasonMerge = {
    s: {// s为开始
      c: 0, // 开始列
      r: 1// 开始取值范围
    },
    e: {// e结束
      c: length, // 结束列
      r: 1// 结束范围
    }
  }
  // 合并所在位置单元格
  const positionMerge = {
    s: {// s为开始
      c: 1, // 开始列
      r: 2// 开始取值范围
    },
    e: {// e结束
      c: length, // 结束列
      r: 2// 结束范围
    }
  }
  const demeArr = []
  for (let i in pubDataMap) {
    demeArr.push(pubDataMap[i].length)
  }
  const jichuangMerge = []
  let inEnd = 1 // eslint-disable-line no-unused-vars
  let inStart = 4
  demeArr.forEach((item, index) => {
    const star = {
      s: {// s为开始
        c: 0, // 开始列
        r: inStart // 开始取值范围
      },
      e: {// e结束
        c: 0, // 结束列
        r: inStart + item// 结束范围
      }
    }
    inStart = inStart + item + 1
    inEnd = inStart + item
    jichuangMerge.push(star)
  })
  // 添加标题，停机原因，所谓位置数据
  const ws = XLSX.utils.aoa_to_sheet([[companyName], [stopReason], [position]])
  // 添加标题栏
  XLSX.utils.sheet_add_aoa(ws, [['分厂/车间']], { origin: 'A3' })
  XLSX.utils.sheet_add_aoa(ws, [[position]], { origin: 'B3' })
  XLSX.utils.sheet_add_aoa(ws, [tableHead], { origin: 'A4' })
  // 添加表格内部数据
  XLSX.utils.sheet_add_aoa(ws, tableData, { origin: 'A5' })
  // 上右下左的border
  const borderAll = { // 单元格外侧框线
    top: {
      style: 'thin'
    },
    bottom: {
      style: 'thin'
    },
    left: {
      style: 'thin'
    },
    right: {
      style: 'thin'
    }
  }
  // 居中
  const alignCenter = {
    horizontal: 'center',
    vertical: 'center'
  }
  // 设置公司名称的样式
  ws['A1'].s = {
    fill: {
      fgColor: {
        rgb: 'FF2F75B5' // 背景颜色,不要在前面加#号
      }
    },
    font: {
      name: '宋体',
      sz: 16,
      color: { rgb: 'FFFFFFFF' },
      bold: false,
      italic: false,
      underline: false
    },
    alignment: alignCenter
  }
  // 设置停机原因的样式
  ws['A2'].s = {
    font: {
      name: '宋体',
      sz: 12,
      color: { rgb: '#FFFF0000' },
      bold: true,
      italic: false,
      underline: false
    },
    alignment: alignCenter
  }
  // 设置所在位置的样式
  ws['A3'].s = {
    font: {
      name: '宋体',
      sz: 12
    },
    alignment: alignCenter
  }
  ws['B3'].s = {
    font: {
      name: '宋体',
      sz: 12
    },
    alignment: alignCenter
  }
  // 创建一个空的sheet
  const wb = XLSX.utils.book_new()
  // 合并单元格
  // if (mergesCell.length > 0) {
  //   if (!ws['!merges']) ws['!merges'] = []
  //   mergesCell.forEach(a => {
  //     a.forEach(item => {
  //       ws['!merges'].push(XLSX.utils.decode_range(item))
  //     })
  //   })
  // }
  // 动态计算每一列的宽度
  const colWidth = [...tableData, [...tableHead]].map(row => row.map(val => {
    /* 先判断是否为null/undefined */
    if (!val) {
      return {
        'wch': 10
      }
      // 判断是否为中文
    } else if (/[\u4e00-\u9fa5]/.test(val.toString())) {
      return {
        'wch': val.toString().length * 2 > 10 ? val.toString().length * 3 : 30
      }
    } else {
      return {
        'wch': val.toString().length > 10 ? val.toString().length : 30
      }
    }
  }))
  // 每一列取最大宽度
  let result = colWidth[0]
  for (let i = 1; i < colWidth.length; i++) {
    for (let j = 0; j < colWidth[i].length; j++) {
      if (result[j]['wch'] < colWidth[i][j]['wch']) {
        result[j]['wch'] = colWidth[i][j]['wch']
      }
    }
  }
  ws['!cols'] = result
  // 给表头动态添加样式
  // 第4行为表头行，通过正则匹配所有第四行
  Object.keys(ws).forEach((item, i) => {
    if (/[A-Z]+4$/.test(item)) {
      ws[item].s = {
        border: borderAll,
        fill: {
          fgColor: {
            rgb: 'FF93CDDD' // 背景颜色,不要在前面加#号
          }
        },
        alignment: alignCenter
      }
      // if (i >= 1) {
      //   headMerge.push({
      //     s: {// s为开始
      //       c: 4 * (i - 1) + 1, // 开始列
      //       r: 3// 开始取值范围
      //     },
      //     e: {// e结束
      //       c: 4 * (i - 1) + 4, // 结束列
      //       r: 3// 结束范围
      //     }
      //   })
      // }
    } else {
      // 内容区的样式，添加border和居中
      if (!ws[item].s && ws[item].t) {
        ws[item].s = {
          border: borderAll,
          alignment: alignCenter
        }
      }
      if (ws[item].v === '小计') {
        ws[item].s = {
          fill: {
            fgColor: {
              rgb: '99cc00' // 背景颜色,不要在前面加#号
            }
          },
          border: borderAll,
          alignment: alignCenter
        }
        ws[item.replace(/B/, 'C')].s = {
          fill: {
            fgColor: {
              rgb: '99cc00' // 背景颜色,不要在前面加#号
            }
          },
          border: borderAll,
          alignment: alignCenter
        }
      }
    }
  })
  // 添加合并的config
  ws['!merges'] = [companyMerge, stopReasonMerge, positionMerge, ...jichuangMerge]
  // 添加sheet
  XLSX.utils.book_append_sheet(wb, ws, '机台报表_生产计数统计')
  const wbout = XLSXStyle.write(wb, {
    bookType: 'xlsx',
    bookSST: false,
    type: 'binary'
  })
  saveAs(new Blob([s2ab(wbout)], {
    type: 'application/octet-stream'
  }), `${excelName}.xlsx`)
}
// 不良原因分析产品明细报表
function exportCustomerExcel (companyName, stopReason, position, tableHead, tableData, excelName, undesirableReason, countTime, sheetName) {
  const length = tableHead.length - 1
  // 合并公司名称
  const companyMerge = {
    s: {// s为开始
      c: 0, // 开始列
      r: 0// 开始取值范围
    },
    e: {// e结束
      c: length, // 结束列
      r: 0// 结束范围
    }
  }
  // 合并停机原因单元格
  const stopReasonMerge = {
    s: {// s为开始
      c: 0, // 开始列
      r: 1// 开始取值范围
    },
    e: {// e结束
      c: length, // 结束列
      r: 1// 结束范围
    }
  }
  // 合并不良原因单元格
  const undesirableReasonMerge = {
    s: {// s为开始
      c: 0, // 开始列
      r: 3// 开始取值范围
    },
    e: {// e结束
      c: length, // 结束列
      r: 3// 结束范围
    }
  }
  // 合并停机原因单元格
  const countTimeMerge = {
    s: {// s为开始
      c: 0, // 开始列
      r: 4// 开始取值范围
    },
    e: {// e结束
      c: length, // 结束列
      r: 4// 结束范围
    }
  }
  // 合并所在位置单元格
  const positionMerge = {
    s: {// s为开始
      c: 0, // 开始列
      r: 2// 开始取值范围
    },
    e: {// e结束
      c: length, // 结束列
      r: 2// 结束范围
    }
  }

  // 添加标题，停机原因，所谓位置数据
  const ws = XLSX.utils.aoa_to_sheet([[companyName], [stopReason], [position], [undesirableReason], [countTime]])

  // 添加标题栏
  XLSX.utils.sheet_add_aoa(ws, [tableHead], { origin: 'A6' })
  // 添加表格内部数据
  XLSX.utils.sheet_add_aoa(ws, tableData, { origin: 'A7' })
  // 上右下左的border
  const borderAll = { // 单元格外侧框线
    top: {
      style: 'thin'
    },
    bottom: {
      style: 'thin'
    },
    left: {
      style: 'thin'
    },
    right: {
      style: 'thin'
    }
  }
  // 居中
  const alignCenter = {
    horizontal: 'center',
    vertical: 'center'
  }
  // 设置公司名称的样式
  ws['A1'].s = {
    fill: {
      fgColor: {
        rgb: 'FF2F75B5' // 背景颜色,不要在前面加#号
      }
    },
    font: {
      name: '宋体',
      sz: 16,
      color: { rgb: 'FFFFFFFF' },
      bold: false,
      italic: false,
      underline: false
    },
    alignment: alignCenter
  }
  // 设置停机原因的样式
  ws['A2'].s = {
    font: {
      name: '宋体',
      sz: 12,
      color: { rgb: '#FFFF0000' },
      bold: true,
      italic: false,
      underline: false
    },
    alignment: alignCenter
  }
  // 设置所在位置的样式
  ws['A3'].s = {
    font: {
      name: '宋体',
      sz: 12
    }
  }
  ws['A4'].s = {
    font: {
      name: '宋体',
      sz: 12
    }
  }
  ws['A5'].s = {
    font: {
      name: '宋体',
      sz: 12
    }
  }
  // 创建一个空的sheet
  const wb = XLSX.utils.book_new()
  // 添加合并的config
  ws['!merges'] = [companyMerge, stopReasonMerge, positionMerge, undesirableReasonMerge, countTimeMerge]
  // 动态计算每一列的宽度
  const colWidth = [...tableData, [...tableHead]].map(row => row.map(val => {
    /* 先判断是否为null/undefined */
    if (!val) {
      return {
        'wch': 10
      }
      // 判断是否为中文
    } else if (/[\u4e00-\u9fa5]/.test(val.toString())) {
      return {
        'wch': val.toString().length * 2 > 10 ? val.toString().length * 2 : 10
      }
    } else {
      return {
        'wch': val.toString().length > 10 ? val.toString().length : 10
      }
    }
  }))
  // 每一列取最大宽度
  let result = colWidth[0]
  for (let i = 1; i < colWidth.length; i++) {
    for (let j = 0; j < colWidth[i].length; j++) {
      if (result[j]['wch'] < colWidth[i][j]['wch']) {
        result[j]['wch'] = colWidth[i][j]['wch']
      }
    }
  }
  ws['!cols'] = result
  // 给表头动态添加样式
  // 第4行为表头行，通过正则匹配所有第四行
  Object.keys(ws).forEach(item => {
    if (/[A-Z]+6$/.test(item)) {
      ws[item].s = {
        border: borderAll,
        fill: {
          fgColor: {
            rgb: 'FF93CDDD' // 背景颜色,不要在前面加#号
          }
        },
        alignment: alignCenter
      }
    } else {
      // 内容区的样式，添加border和居中
      if (!ws[item].s && ws[item].t) {
        ws[item].s = {
          border: borderAll,
          alignment: alignCenter
        }
      }
    }
  })
  // 添加sheet
  XLSX.utils.book_append_sheet(wb, ws, sheetName)
  const wbout = XLSXStyle.write(wb, {
    bookType: 'xlsx',
    bookSST: false,
    type: 'binary'
  })
  saveAs(new Blob([s2ab(wbout)], {
    type: 'application/octet-stream'
  }), `${excelName}.xlsx`)
}
export default {
  sheet2blob,
  openDownloadDialog,
  exportCustomExcel,
  exportCustomerExcel
}
